package com.xing.lei.happy.utils;


import com.xing.lei.happy.dao.Column;
import com.xing.lei.happy.dao.Table;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.*;


@SuppressWarnings("unchecked")
public class DatabaseUtils {
	private static final Map<DataSource, String> databaseProductNames = new HashMap<DataSource, String>();
	private static final Map<DataSource, Table> tables = new HashMap<DataSource, Table>();
	private static DataSource defaultDataSource;

	public static DataSource getDefaultDataSource() {
		return defaultDataSource;
	}

	public static void setDefaultDataSource(DataSource defaultDataSource) {
		DatabaseUtils.defaultDataSource = defaultDataSource;
	}

	private static String getDatabaseProductName(DataSource dataSource) {
		if (ObjectUtils.isBlank(dataSource)) {
			dataSource = getDefaultDataSource();
		}
		if (ObjectUtils.isBlank(dataSource)) {
			return null;
		}
		if (MapUtils.notContainsKey(databaseProductNames, dataSource)) {
			synchronized (databaseProductNames) {
				if (MapUtils.notContainsKey(databaseProductNames, dataSource)) {
					Connection connection = null;
					try {
						connection = dataSource.getConnection();
						databaseProductNames.put(dataSource, connection
								.getMetaData().getDatabaseProductName());
					} catch (Exception e) {
						databaseProductNames.put(dataSource, null);
					} finally {
						close(connection);
					}
				}
			}
		}
		return databaseProductNames.get(dataSource);
	}

	public static Table getTable(DataSource dataSource) {
		if (ObjectUtils.isBlank(dataSource)) {
			dataSource = getDefaultDataSource();
		}
		if (ObjectUtils.isBlank(dataSource)) {
			return null;
		}
		if (MapUtils.notContainsKey(tables, dataSource)) {
			synchronized (tables) {
				if (MapUtils.notContainsKey(tables, dataSource)) {
					Connection connection = null;
					try {
						connection = dataSource.getConnection();
						tables.put(dataSource, new Table(dataSource));
					} catch (Exception e) {
						tables.put(dataSource, null);
					} finally {
						close(connection);
					}
				}
			}
		}
		return tables.get(dataSource);
	}

	public static void close(Object... arr) {
		try {
			if (ArrayUtils.isNotEmpty(arr)) {
				for (Object obj : arr) {
					if (obj instanceof Connection) {
						((Connection) obj).close();
					} else if (obj instanceof Statement) {
						((Statement) obj).close();
					} else if (obj instanceof ResultSet) {
						((ResultSet) obj).close();
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static Map<String, Column> getColumns(DataSource dataSource,
												 Object obj) {
		Table table = getTable(dataSource);
		return table == null ? null : table.getColumns(obj);
	}

	public static Map<String, Column> getColumns(Object obj) {
		return getColumns(null, obj);
	}

	public static Column getColumn(DataSource dataSource, Object obj,
			String name) {
		Table table = getTable(dataSource);
		return table == null ? null : table.getColumn(obj, name);
	}

	public static Column getColumn(Object obj, String name) {
		return getColumn(null, obj, name);
	}

	public static boolean hasColumn(DataSource dataSource, Object obj,
			String name) {
		Table table = getTable(dataSource);
		return table == null ? null : table.hasColumn(obj, name);
	}

	public static boolean hasColumn(Object obj, String name) {
		return hasColumn(null, obj, name);
	}

	public static Column getPrimaryColumn(DataSource dataSource, Object obj) {
		Table table = getTable(dataSource);
		return table == null ? null : table.getPrimaryColumn(obj);
	}

	public static Column getPrimaryColumn(Object obj) {
		return getPrimaryColumn(null, obj);
	}

	public static String getPrimaryField(DataSource dataSource, Object obj) {
		Column column = getPrimaryColumn(dataSource, obj);
		return column == null ? null : column.getField();
	}

	public static String getPrimaryField(Object obj) {
		return getPrimaryField(null, obj);
	}

	public static boolean isRidColumn(DataSource dataSource, Object obj) {
		Column column = getPrimaryColumn(dataSource, obj);
		if (column == null) {
			return false;
		}
		Class<?> fieldType = column.getFieldType();
		Integer size = column.getSize();
		return fieldType == String.class && NumberUtils.equals(size, 32);
	}

	public static boolean isRidColumn(Object obj) {
		return isRidColumn(null, obj);
	}

	public static String getPrimaryKey(DataSource dataSource, Object obj) {
		Column column = getPrimaryColumn(dataSource, obj);
		return column == null ? null : column.getName();
	}

	public static String getPrimaryKey(Object obj) {
		return getPrimaryKey(null, obj);
	}

	public static boolean hasPrimaryColumn(DataSource dataSource, Object obj) {
		Table table = getTable(dataSource);
		return table == null ? null : table.hasPrimaryColumn(obj);
	}

	public static boolean hasPrimaryColumn(Object obj) {
		return hasPrimaryColumn(null, obj);
	}

	public static boolean parseMysql(DataSource dataSource) {
		String databaseProductName = getDatabaseProductName(dataSource);
		return StringUtils.test(databaseProductName, "(?i)mysql");
	}

	public static boolean parseOracle(DataSource dataSource) {
		String databaseProductName = getDatabaseProductName(dataSource);
		return StringUtils.test(databaseProductName, "(?i)oracle");
	}

	public static boolean parseSqlserver(DataSource dataSource) {
		String databaseProductName = getDatabaseProductName(dataSource);
		return StringUtils.test(databaseProductName, "(?i)sql server");
	}

/*
	public static List<Map<String, String>> selectSql(DataSource dataSource,
			String sql) {
		List<Map<String, String>> result = null;
		Connection connection = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			if (ObjectUtils.isBlank(dataSource)) {
				dataSource = getDefaultDataSource();
			}
			if (ObjectUtils.isNotBlank(dataSource)) {
				connection = dataSource.getConnection();
				stmt = connection.createStatement();
				rs = stmt.executeQuery(sql);
				while (rs.next()) {
					Map<String, String> map = new HashMap<String, String>();
					ResultSetMetaData rsmd = rs.getMetaData();
					for (int i = 1, len = rsmd.getColumnCount(); i <= len; i++) {
						String name = rsmd.getColumnName(i);
						map.put(DatabaseUtils.hump(name), rs.getString(name));
					}
					if (result == null) {
						result = new ArrayList<Map<String, String>>();
					}
					result.add(map);
				}
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			close(connection, stmt, rs);
		}
		return result;
	}
*/



/*	public static void setNullsLast(Map paramMap) {
		if (paramMap != null) {
			String str = MapUtils.getString(paramMap, "orderByClause");
			if (StringUtils.isNotBlank(str)) {
				paramMap.put("orderByClause", str.replaceAll("([^,]+)",
						"$1 nulls last"));
			}
		}
	}*/

	public static String underline(Object obj) {
		if (obj == null) {
			return null;
		} else if (obj instanceof String) {
			return StringUtils.humpToUnderline((String) obj).toLowerCase();
		} else {
			String instanceName = ObjectUtils.getInstanceName(obj);
			return StringUtils.humpToUnderline(instanceName).toLowerCase();
		}
	}

	public static String hump(Object obj) {
		String str = ObjectUtils.toString(obj,"");
		if (StringUtils.notTest(str, "[a-z]")) {
			str = StringUtils.lowerCase(str);
		}
		return StringUtils.underlineToHump(str);
	}
}